package com.salinity.kun.helper;

import java.util.List;

import com.salinity.kun.algorithm.harmonic.GaussianElimination;
import com.salinity.kun.algorithm.harmonic.PCA;

import Jama.Matrix;

public class PCAHelper {

	private double[][] primaryArray;
	private double[][] fb;

	public PCAHelper(double[][] primaryArray, double[][] fb) {
		this.primaryArray = primaryArray;
		this.fb = fb;

	}

	public Matrix doPCA() {
		PCA pca = new PCA();
		double[][] averageArray = pca.changeAverageToZero(primaryArray);

		double[][] varMatrix = pca.getVarianceMatrix(averageArray);

		double[][] eigenvalueMatrix = pca.getEigenvalueMatrix(varMatrix);

		double[][] eigenVectorMatrix = pca.getEigenVectorMatrix(varMatrix);

		List<Matrix> rsltList = pca.getPrincipalComponent_V2(primaryArray, eigenvalueMatrix, eigenVectorMatrix);
		Matrix eigenValueRslt = rsltList.get(0);
		Matrix principalMatrix = rsltList.get(1);
		Matrix CTB = pca.inverseDiagonalMatrix(eigenValueRslt).times(principalMatrix.inverse()).times(new Matrix(fb));
		Matrix rsltMatrix = CTB.transpose().times(principalMatrix.transpose());
		return rsltMatrix;
	}
	
	/**
	 * 
	 * @return
	 */
	@Deprecated
	public Matrix doPCA_V2() {
		PCA pca = new PCA();

		Matrix m = new Matrix(primaryArray);
		Matrix fbm = new Matrix(fb);

		MatrixHelper.printMatrix(m.getArray(), ",");
		fbm = fbm.times(1 / primaryArray[0][0]);
		m = m.times(1 / primaryArray[0][0]);

		Matrix A = m.transpose().times(m);

		double[][] eigenvalueMatrix = pca.getEigenvalueMatrix(A.getArray());

		double[][] eigenVectorMatrix = pca.getEigenVectorMatrix(A.getArray());

		List<Matrix> rsltList = pca.getPrincipalComponent_V2(primaryArray, eigenvalueMatrix, eigenVectorMatrix);
		Matrix eigenValueRslt = rsltList.get(0);
		Matrix principalMatrix = rsltList.get(1);
		Matrix CTB = pca.inverseDiagonalMatrix(eigenValueRslt).times(principalMatrix.inverse()).times(fbm);
		Matrix rsltMatrix = CTB.transpose().times(principalMatrix.transpose());
		rsltMatrix.print(4, 6);
		return rsltMatrix;

	}
	
	
	public void findPCRParam() {
		PCA pca = new PCA();
		
		Matrix m = new Matrix(primaryArray);
		Matrix mfb = new Matrix(fb);
		
		mfb=mfb.times(1/m.get(0, 0));
		
		m=m.times(1/m.get(0, 0));
		double[][] eigenvalueMatrix = pca.getEigenvalueMatrix(m.getArray());
		
	
		
		double[][] eigenVectorMatrix = pca.getEigenVectorMatrix(m.getArray());
		Matrix rsltMatrix=null;
		int j;
		for(int i=1;i<=m.getRowDimension();i++) {
			Matrix eigenValueRslt = pca.getPrincipalComponentValMatrix(eigenvalueMatrix,i);
			
			//eigenValueRslt.print(4, 6);
			Matrix principalMatrix = new Matrix(eigenVectorMatrix);
			Matrix CTB = pca.inverseDiagonalMatrix(eigenValueRslt).times(principalMatrix.inverse()).times(mfb);
			rsltMatrix = CTB.transpose().times(principalMatrix.transpose());
			double[] tempParams = rsltMatrix.getArray()[0];
			System.out.printf("%.6f\t",tempParams[0]);
			for (j = 1; j+1 < tempParams.length; j += 2) {
				System.out.printf("%.6f\t",
						Math.sqrt(tempParams[j] * tempParams[j] + tempParams[j + 1] * tempParams[j + 1]));
			}

			System.out.println();
			
		}
	}
	
	public Matrix doPCR_V1(int index) {
		PCA pca = new PCA();
		
		Matrix m = new Matrix(primaryArray);
		Matrix mfb = new Matrix(fb);
		
		mfb=mfb.times(1/m.get(0, 0));
		
		m=m.times(1/m.get(0, 0));
		MatrixHelper.printMatrix(m.getArray(),"\t");
		//MatrixHelper.printMatrix(mfb.transpose().getArray(),"\t");
		double[][] eigenvalueMatrix = pca.getEigenvalueMatrix(m.getArray());
		//MatrixHelper.printMatrix(eigenvalueMatrix,"\t");
		double[][] eigenVectorMatrix = pca.getEigenVectorMatrix(m.getArray());
		//MatrixHelper.printMatrix(eigenVectorMatrix,"\t");		
		Matrix eigenValueRslt = pca.getPrincipalComponentValMatrix(eigenvalueMatrix,index);
		//MatrixHelper.printMatrix(new Matrix(eigenVectorMatrix).times(new Matrix(eigenVectorMatrix).transpose()).getArray());
		Matrix principalMatrix = new Matrix(eigenVectorMatrix);
		Matrix CTB = pca.inverseDiagonalMatrix(eigenValueRslt).times(principalMatrix.inverse()).times(mfb);
		Matrix rsltMatrix = CTB.transpose().times(principalMatrix.transpose());
		return rsltMatrix;
	}

}
